// Copyright Epic Games, Inc. All Rights Reserved.

#include "GameFeatureAction_AddWidget.h"
#include "Components/GameFrameworkComponentManager.h"
#include "Engine/GameInstance.h"
#include "GameFeatures/GameFeatureAction_WorldActionBase.h"
#include "GameFeaturesSubsystemSettings.h"
#include "CommonUIExtensions.h"
#include "UI/LyraHUD.h"

#if WITH_EDITOR
#include "Misc/DataValidation.h" // 数据验证相关
#endif

#include UE_INLINE_GENERATED_CPP_BY_NAME(GameFeatureAction_AddWidget) // 包含自动生成的代码

#define LOCTEXT_NAMESPACE "LyraGameFeatures" // 定义本地化文本命名空间

//////////////////////////////////////////////////////////////////////
// UGameFeatureAction_AddWidgets

/**
 * 游戏特性停用时调用
 */
void UGameFeatureAction_AddWidgets::OnGameFeatureDeactivating(FGameFeatureDeactivatingContext& Context)
{
	Super::OnGameFeatureDeactivating(Context); // 调用父类方法

	FPerContextData* ActiveData = ContextData.Find(Context); // 查找上下文数据
	if ensure(ActiveData) // 确保数据有效
	{
		Reset(*ActiveData); // 重置数据
	}
}

#if WITH_EDITORONLY_DATA
/**
 * 添加额外的资源包数据
 */
void UGameFeatureAction_AddWidgets::AddAdditionalAssetBundleData(FAssetBundleData& AssetBundleData)
{
	for (const FLyraHUDElementEntry& Entry : Widgets) // 遍历控件条目
	{
		AssetBundleData.AddBundleAsset(UGameFeaturesSubsystemSettings::LoadStateClient, Entry.WidgetClass.ToSoftObjectPath().GetAssetPath()); // 添加资源包资源
	}
}
#endif

#if WITH_EDITOR
/**
 * 数据验证方法
 */
EDataValidationResult UGameFeatureAction_AddWidgets::IsDataValid(FDataValidationContext& Context) const
{
	EDataValidationResult Result = CombineDataValidationResults(Super::IsDataValid(Context), EDataValidationResult::Valid); // 组合数据验证结果

	{
		int32 EntryIndex = 0; // 条目索引
		for (const FLyraHUDLayoutRequest& Entry : Layout) // 遍历布局
		{
			if (Entry.LayoutClass.IsNull()) // 检查布局类是否为空
			{
				Result = EDataValidationResult::Invalid; // 设置为无效
				Context.AddError(FText::Format(LOCTEXT("LayoutHasNullClass", "Layout中索引{0}处的WidgetClass为空"), FText::AsNumber(EntryIndex))); // 添加错误信息
			}

			if (!Entry.LayerID.IsValid()) // 检查层ID是否有效
			{
				Result = EDataValidationResult::Invalid; // 设置为无效
				Context.AddError(FText::Format(LOCTEXT("LayoutHasNoTag", "Widgets中索引{0}处的LayerID未设置"), FText::AsNumber(EntryIndex))); // 添加错误信息
			}

			++EntryIndex; // 递增条目索引
		}
	}

	{
		int32 EntryIndex = 0; // 条目索引
		for (const FLyraHUDElementEntry& Entry : Widgets) // 遍历控件
		{
			if (Entry.WidgetClass.IsNull()) // 检查控件类是否为空
			{
				Result = EDataValidationResult::Invalid; // 设置为无效
				Context.AddError(FText::Format(LOCTEXT("EntryHasNullClass", "Widgets中索引{0}处的WidgetClass为空"), FText::AsNumber(EntryIndex))); // 添加错误信息
			}

			if (!Entry.SlotID.IsValid()) // 检查插槽ID是否有效
			{
				Result = EDataValidationResult::Invalid; // 设置为无效
				Context.AddError(FText::Format(LOCTEXT("EntryHasNoTag", "Widgets中索引{0}处的SlotID未设置"), FText::AsNumber(EntryIndex))); // 添加错误信息
			}
			++EntryIndex; // 递增条目索引
		}
	}

	return Result; // 返回结果
}
#endif

/**
 * 添加到世界的方法
 */
void UGameFeatureAction_AddWidgets::AddToWorld(const FWorldContext& WorldContext, const FGameFeatureStateChangeContext& ChangeContext)
{
	UWorld* World = WorldContext.World(); // 获取世界
	UGameInstance* GameInstance = WorldContext.OwningGameInstance; // 获取游戏实例
	FPerContextData& ActiveData = ContextData.FindOrAdd(ChangeContext); // 查找或添加上下文数据

	if ((GameInstance != nullptr) && (World != nullptr) && World->IsGameWorld()) // 检查游戏实例和世界是否有效
	{
		if (UGameFrameworkComponentManager* ComponentManager = UGameInstance::GetSubsystem<UGameFrameworkComponentManager>(GameInstance)) // 获取组件管理器
		{			
			TSoftClassPtr<AActor> HUDActorClass = ALyraHUD::StaticClass(); // HUD Actor类

			TSharedPtr<FComponentRequestHandle> ExtensionRequestHandle = ComponentManager->AddExtensionHandler( // 创建扩展请求句柄
				HUDActorClass,
				UGameFrameworkComponentManager::FExtensionHandlerDelegate::CreateUObject(this, &ThisClass::HandleActorExtension, ChangeContext)); // 绑定到处理函数
			ActiveData.ComponentRequests.Add(ExtensionRequestHandle); // 添加组件请求
		}
	}
}

/**
 * 重置数据的方法
 */
void UGameFeatureAction_AddWidgets::Reset(FPerContextData& ActiveData)
{
	ActiveData.ComponentRequests.Empty(); // 清空组件请求

	for (TPair<FObjectKey, FPerActorData>& Pair : ActiveData.ActorData) // 遍历Actor数据
	{
		for (FUIExtensionHandle& Handle : Pair.Value.ExtensionHandles) // 遍历扩展句柄
		{
			Handle.Unregister(); // 取消注册句柄
		}
	}
	ActiveData.ActorData.Empty(); // 清空Actor数据
}

/**
 * 处理Actor扩展的方法
 */
void UGameFeatureAction_AddWidgets::HandleActorExtension(AActor* Actor, FName EventName, FGameFeatureStateChangeContext ChangeContext)
{
	FPerContextData& ActiveData = ContextData.FindOrAdd(ChangeContext); // 查找或添加上下文数据
	if ((EventName == UGameFrameworkComponentManager::NAME_ExtensionRemoved) || (EventName == UGameFrameworkComponentManager::NAME_ReceiverRemoved)) // 检查是否是移除事件
	{
		RemoveWidgets(Actor, ActiveData); // 移除控件
	}
	else if ((EventName == UGameFrameworkComponentManager::NAME_ExtensionAdded) || (EventName == UGameFrameworkComponentManager::NAME_GameActorReady)) // 检查是否是添加事件
	{
		AddWidgets(Actor, ActiveData); // 添加控件
	}
}

/**
 * 添加控件的方法
 */
void UGameFeatureAction_AddWidgets::AddWidgets(AActor* Actor, FPerContextData& ActiveData)
{
	ALyraHUD* HUD = CastChecked<ALyraHUD>(Actor); // 转换为Lyra HUD

	if (!HUD->GetOwningPlayerController()) // 检查是否有拥有者玩家控制器
	{
		return; // 没有则返回
	}

	if (ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(HUD->GetOwningPlayerController()->Player)) // 获取本地玩家
	{
		FPerActorData& ActorData = ActiveData.ActorData.FindOrAdd(HUD); // 查找或添加Actor数据

		for (const FLyraHUDLayoutRequest& Entry : Layout) // 遍历布局
		{
			if (TSubclassOf<UCommonActivatableWidget> ConcreteWidgetClass = Entry.LayoutClass.Get()) // 获取具体控件类
			{
				ActorData.LayoutsAdded.Add(UCommonUIExtensions::PushContentToLayer_ForPlayer(LocalPlayer, Entry.LayerID, ConcreteWidgetClass)); // 推送内容到层
			}
		}

		UUIExtensionSubsystem* ExtensionSubsystem = HUD->GetWorld()->GetSubsystem<UUIExtensionSubsystem>(); // 获取UI扩展子系统
		for (const FLyraHUDElementEntry& Entry : Widgets) // 遍历控件
		{
			ActorData.ExtensionHandles.Add(ExtensionSubsystem->RegisterExtensionAsWidgetForContext(Entry.SlotID, LocalPlayer, Entry.WidgetClass.Get(), -1)); // 注册扩展为控件
		}
	}
}

/**
 * 移除控件的方法
 */
void UGameFeatureAction_AddWidgets::RemoveWidgets(AActor* Actor, FPerContextData& ActiveData)
{
	ALyraHUD* HUD = CastChecked<ALyraHUD>(Actor); // 转换为Lyra HUD

	// 仅当这是注册的相同HUD Actor时才取消注册，客户端上可能同时有多个活跃的
	FPerActorData* ActorData = ActiveData.ActorData.Find(HUD); // 查找Actor数据

	if (ActorData) // 检查数据存在
	{
		for (TWeakObjectPtr<UCommonActivatableWidget>& AddedLayout : ActorData->LayoutsAdded) // 遍历已添加的布局
		{
			if (AddedLayout.IsValid()) // 检查布局有效
			{
				AddedLayout->DeactivateWidget(); // 停用控件
			}
		}

		for (FUIExtensionHandle& Handle : ActorData->ExtensionHandles) // 遍历扩展句柄
		{
			Handle.Unregister(); // 取消注册句柄
		}
		ActiveData.ActorData.Remove(HUD); // 移除Actor数据
	}
}

#undef LOCTEXT_NAMESPACE // 取消定义本地化文本命名空间